MySQL InnoDB アーキテクチャ
https://scrapbox.io/files/6389ab4d901000001de9041b.png
メモリー上のメンバ
hr.icon
Buffer Pool
特徴
頻繁にアクセスされるデータのキャッシュ。
メインメモリー内の領域。
ここのサイズが大きいと持っておけるデータ量も増えて、MySQLの性能が向上する。
データの保持戦略には「LRUアルゴリズム」を採用
もしバッファプールが埋まってる場合は、最近最も使用されてないページが弾かれ、新しいページがリストの中央に追加される。 構造
中央のミッドポイントを元に2つのサブリスト(若いリスト、古いリスト)に分かれる
https://scrapbox.io/files/6390a168ec9939001dfee4d2.png
アルゴリズムの説明
バッファプール内に無いページを読み込む際は、中央にページを追加する
バッファプール内に存在するページを読み込んだ場合、若いリストの一番先頭に移動させる
リストがいっぱいになったら、古いリストの最後方から削除されていく
その他
バッファプールは大きい方が性能面でいいが、物理メモリを占有し過ぎないように注意した方がいい。MySQL以外のプロセスもメモリを利用できるようにしておくこと。
大きなデータ範囲を一旦メモリに落とすとかしちゃうと、頻繁に利用するページが削除されちゃうので注意してね。
フルスキャンとかには気をつけなはれ
Log Buffer
特徴
ディスク上のRedo Logに書き込むデータをメモリ上に保持するための領域。
Log Bufferのサイズはデフォルトで16MB。
Log Bufferの内容は定期的にディスクにフラッシュされる。
これは誤解を生むので注意
innodb_flush_log_at_trx_commit=0の時は、1秒に1回ログファイルにフラッシュされる
innodb_flush_log_at_trx_commit=1の時は、COMMITが実施される度にそのログファイルにフラッシュされる
ログバッファのDisk書き込みタイミング
性能周りのポイント
Log Bufferのサイズを大きく取っておくと、トランザクションがコミットされる前にRedo Logに書き込まれるということが無くなりやすい。
もしコミット前に書き込みなんてことがあると、IO回数が増えて性能劣化につながる。
というわけで、大きいトランザクション(1回のコミットで多行の更新・挿入・削除)があるワークロードだと、Log Bufferのサイズを大きくしておくべき
Change Buffer
特徴
セカンダリインデックスの挿入・変更・削除内容をメモリ上に保持するための領域。
ただし、対象のセカンダリインデックスがBuffer Poolに存在しない場合のみ利用される
このメモリがもしなかったとしたら、、、セカンダリインデックスを貼ってるデータの更新を行なう際に、インデックス内容の更新でディスクアクセスが発生して性能悪化に繋がる。
その性能悪化が起きないように、メモリ領域が用意されている。
一定の間隔でバックグラウンドスレッドが、メモリの内容をディスクにフラッシュするようになってる。
これによってIOの削減ができる。
障害発生時の回復はどうなる?
普通のクラッシュリカバリと同じように、Redo Logの内容を使って回復できる。
メリット
ページはメモリ内で何度か変更して、一度だけディスクに流すことができます。
ダーティなページはまとめてフラッシュされるので、IO処理の回数が少なくなります。
適応型インデックスバッファ(AHI)
特徴
前提として、セカンダリインデックスを使った検索では、セカンダリから主キーを検索して、その主キーを用いてレコードを検索する仕組みになってる。
2回ディスク検索が挟まることから、主キー検索よりセカンダリ検索の方が時間がかかる。
「このよく使われるインデックス検索をバッファで保持しておこう」というのが、この適応型インデックスバッファの目的。
並列数が多いと、メモリ上でロックが起きたりする
AHIのデメリットとして、同時にこのAHIを利用する輩が多すぎると、ロックが発生して性能悪化に繋がるというのがある。
気をつけられたし。
ディスク上のメンバ
hr.icon
二重書き込みバッファ(ダブルライトバッファ、doublewrite buffer)
特徴
バッファプールからデータがフラッシュされる際、データファイルに書き込む前に書き込まれるディスク領域。
シーケンシャルIOで書き込まれるので、書き込み自体は早いらしい。
このバッファへの書き込みフラッシュが完了した後に、InnoDBはデータファイルの正しい位置にデータを書き込む。
なぜ必要なのか
テーブルスペース(ストレージ)を更新中にOSがクラッシュしてデータ不整合が起きないようにするために存在。
ダブルバッファに先に書き込んでおけば、テーブルスペースに書き込み途中でDBが落ちたとしても次のロジックで回復可能。
1. ダブルライトバッファへの更新が中途半端になった場合、ダブルライトバッファの内容を破棄する。(テーブルスペースでの不整合は無し)
2. テーブルスペースへの更新が中途半端になった場合、ダブルライトバッファの内容で該当するページを更新する。
ONにしてる場合の性能面
まあ、OFFの場合よりは性能劣化はそりゃある。IO増えるんだから。
OFFにして限界を速さとスリルを楽しむのもいいが、データは壊れやすくなる。
疑問
q.icon ダブルライトバッファ書き込み途中にOSが落ちた場合、Redoログにはトランザクションはまだ残ってるのか?
a.icon 別に、チェックポイントを実行してすぐ対象のredoログがすぐ削除されるとかない。
なので、ダブルライトバッファ書き込み中に失敗したデータとかは、Redoログから復元できるようになってる。
神資料
ポイント
クラッシュリカバリ時のredoログの挙動
redoログはバッファプールに対して変更を加えるのであって、ディスクに直接変更を加えることはない。
なので、バッファプールにディスクからデータ読み取りした際、データがバグってたら回復できない。
(推測)redoログは、ディスクの最新LSNだかなんだかを見て、そのLSN以降で自分が持ってる全てのトランザクションログをバッファプールに反映する
ダブルライトバッファがなぜ必要か
もしこいつ無しでcheckpoint後にディスク書き込みする場合、途中でクラッシュしたらディスク内で不整合が起きたまま保存される。
これを回復するのはredoログからではできないらしい。(理由がまだちゃんとわかってない)
もしダブルライトバッファがあればいけるらしい。
checkpointが起きた際、その時のフラッシュ対象ページを一旦全てダブルライトバッファに保存するとのこと。
全てのページが反映された後に、テーブル上に更新しにいくと。
なので、ダブルライトバッファに書き込み途中で落ちた場合は、テーブルの方が汚れなくて済むし。
テーブルが汚れないので、redoログから復活させることが可能。
ダブルライトバッファからテーブルに書き込んでる際にクラッシュ落ちた場合は...
(おそらく)ダブルライトバッファのデータ内容が、ディスクが汚れたとしても、再度書き込んで回復させれるような仕組みになってそう。
Undo Log
特徴
あるレコードにUPDATEが行われた際に「更新前の状態」を保存するためのディスク領域。
Undoテーブルスペースって領域にある。
以下2つの用途で利用されることが多い。
1. トランザクションのロールバック
2. MVCCの実現
Redo Log
イメージ理解してるので省略...(後で記載)
System Table Space
特徴
新しいバージョンだと、基本的には「Change Buffer」の永続領域になってる。
古いバージョンだと、二重書き込みバッファ用の領域になったりもしてる。
あと、1テーブル1ファイルの設定じゃ無い場合、テーブルデータがこのシステムテーブルスペースに入ることもある。
File-Per-Table Space
特徴
設定ON時のみ、1テーブル毎に確保されるテーブルスペース。
1テーブル1ファイルの要領。
利点などの詳細は以下
注意点
テーブルサイズ自体が、OSのファイルサイズ制限の影響を受けるので気をつけて。
一般テーブルスペース
あまり重要そうじゃ無いので、一旦省略。
一時テーブル(Temporary Table)
参考